/*
	JWIM - Javascript Windowmanager for Independent Modules
	
	Copyright (c) 2010 Filippo Cavallarin - poplix@papuasia.org
	
	Version: 0.8 2012-06-09
	Updated by allidylls@gmail.com
	
	Licensed under the MIT license http://www.opensource.org/licenses/mit-license.php
	
	Permission is hereby granted, free of charge, to any person obtaining a copy
	of this software and associated documentation files (the "Software"), to deal
	in the Software without restriction, including without limitation the rights
	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
	copies of the Software, and to permit persons to whom the Software is
	furnished to do so, subject to the following conditions:
	
	The above copyright notice and this permission notice shall be included in
	all copies or substantial portions of the Software.
	
	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
	THE SOFTWARE.

*/

var jwim = {
	Utils: {},
	Scope: function(thisw) {
		this.thisw = thisw;
		this._eval = function(s) {
		    eval(s);
		};
	}
};


/* - - MANAGER CLASS - - */
// constructor
jwim.Manager = function(options){
	this.windows = [];
	this.nextid = 1;
	this.selectedWindow = null;		
	this.mouse = {cur:{x:0,y:0}, click:{x:0,y:0}};
	this.draggingWin = null;
	
	this.opts={
		classWindow:'jwimWindow',
		classActiveWindow:'jwimActiveWindow',
		classContent: (jwim.Utils.BROWSER === 'safari' ? 'jwimContentSafari' : 'jwimContent'),
		classFrame: 'jwimFrame',
		classTitle:'jwimTitle',
		classIcon:'jwimTaskBarIcon',
		classActiveIcon:'jwimActiveTaskBarIcon',
		baseZIndex:5000,
		alwaysShowIcons:true,
		taskbar:null,
		container:document.body,
		showTitleBar:true,
		showMaximizer:true,
		showIconizer:true,
		showClose:true,
		showIconImage: true,
		iconImageURL: '',
		defaultX:32,
		defaultY:32,
		defaultWidth:500,
		defaultHeight:300,
		defaultState:'window',
		shiftOffset:32,
		movable:true,
		httpErrorHandler:null,
		autoCheckResize:true,
		containerBoundaries:64,
		iconWidth: 180,
		resizeIcons:true,
		afterLoad:null,
		cacheXHR:false
	};

	if(typeof options === 'object') {
		for(var a in options) {
		    this.opts[a]=options[a];
		}
	}
	
	if(this.opts.autoCheckResize) {
	    jwim.Utils.addEvent(window, 'resize', jwim.Utils.bind(this.checkResize, this));
	}
};

jwim.Manager.prototype.createWindow = function(opts) {
	opts = opts || {};

    // one window one id
	if(opts.id && this.getWindow(opts.id) != null) {
	    return null;
	}
	
	var container = opts.container || this.opts.container;
	var state = opts.state || this.opts.defaultState;
	
	var w = new jwim.Window(opts, this);
	
	w.win = document.createElement('div');		
	w.content = document.createElement('div');
	w.loading = document.createElement('div');

	if (this.opts.shiftOffset > 0) {
		var a;
		do {
			for(a=0; a<this.windows.length; a++){
				var p = this.windows[a];
				if( (p.x===w.x || p.userX===w.x) && (p.y===w.y || p.userY===w.y) ){
					w.x += this.opts.shiftOffset;
					w.y += this.opts.shiftOffset;
					break;
				}
			}
		} while(a != this.windows.length);
	}

	w.userX = w.x;
	w.userY = w.y;
	w.win.className = this.opts.classWindow;
	w.win.style.cssText = "z-index:"+this.opts.baseZIndex+";position:absolute;top:"+(w.y)+"px;left:"+(w.x)+"px;";				
	
	//margins and position on content are not allowed
	// IMPORTANT: init width n height
	w.content.className = this.opts.classContent;
	w.content.style.cssText = 'position:relative;margin:0;width:0px;height:0px';
	
	if(this.opts.showTitleBar){
		w.title = document.createElement('div');
		w.title.className = this.opts.classTitle;
		
		if (this.opts.showIconImage) {
		    w.components.iconImage = document.createElement('img');
		    w.components.iconImage.className = 'jwimIconImage';
		    w.components.iconImage.src = w.iconImageURL;
		    w.title.appendChild(w.components.iconImage);
		}
		
		w.titleSpan = document.createElement('div');
		w.titleSpan.className = 'jwimTitleText';
		w.titleSpan.innerHTML = w.titleText;
		w.title.appendChild(w.titleSpan);
		
		if(this.opts.showClose){	
			w.components.close = document.createElement('div');	
			w.components.close.className = 'jwimCloseBox';
			w.title.appendChild(w.components.close);
		}
		
		if(this.opts.showMaximizer) {
			w.components.maximizer = document.createElement('div');		
			w.components.maximizer.className = 'jwimMaxBox';
			w.title.appendChild(w.components.maximizer);
		}
		
		if(this.opts.taskbar && this.opts.showIconizer) {
			w.components.iconizer = document.createElement('div');			
			w.components.iconizer.className = 'jwimMinBox';
			w.title.appendChild(w.components.iconizer);
		}
		
		w.win.appendChild(w.title);
		w.components.titlebar = w.title;
	} 

	w.win.appendChild(w.content);
	w.components.content = w.content;
	
	w.loading.className = 'jwimLoading';
	if(w.title) {
		w.title.appendChild(w.loading);
    }
	else {
	    w.win.appendChild(w.loading);
	}
	
	w.components.loading = w.loading;

	container.appendChild(w.win);
	w.components.window = w.win;
	w._setSize(w.w,w.h,false,'');
	this.windows.push(w);
	
	if(this.opts.taskbar && this.opts.alwaysShowIcons) {
	    w._createTaskbarIcon();
	}
	
	this._selectWindow(w, true);
	if(state != 'window') {
	    w.setState(state);
	}
    
    w.attachEvents();
    
    w.closeConfirm = opts.closeConfirm || '';
    
	return w;
};


jwim.Manager.prototype.getWindow = function(id) {
    var a
	for(var a=0; a< this.windows.length; a++){
		if(this.windows[a].id == id) return this.windows[a];
	}
	return null;
};


jwim.Manager.prototype.getSelectedWindow=function(){ 
	return this.selectedWindow;
};


jwim.Manager.prototype.getAllWindows=function(){
	var ret=[];
	for(var a = this.windows.length-1; a >=0  ; a--){
		ret.push(this.windows[a]);
	}
	return ret;
};


jwim.Manager.prototype.getContainerHeight=function(){
	if(this.opts.container == document.body)
		return jwim.Utils.getBodySize().height;
		
	return this.opts.container.clientHeight;

};


jwim.Manager.prototype.getContainerWidth=function(){
	if(this.opts.container == document.body)
		return jwim.Utils.getBodySize().width;

	return this.opts.container.clientWidth;
};


jwim.Manager.prototype.checkResize=function(){
	for(var a=0; a< this.windows.length;a++){
		if(this.windows[a].state != 'maximized')continue;
	
		var Dw= this.windows[a].win.offsetWidth - parseInt(this.windows[a].win.style.width);
		var Dh= this.windows[a].win.offsetHeight - parseInt(this.windows[a].win.style.height);	
		var w=this.windows[a].getContainerWidth()  - Dw;
		var h=this.windows[a].getContainerHeight() - Dh;
		
		this.windows[a]._setSize(w,h,false,'resize');	
	}
	
	if(this.opts.taskbar && this.opts.resizeIcons)
		this._resizeIcons();
}


jwim.Manager.prototype._getNewId=function(){
	var id=this.nextid;
	this.nextid++;
	return id;
};


jwim.Manager.prototype._selectWindow=function(win){
	
	// if win.scope==null the win has been closed and this is the result of event propagation
	if(win == this.selectedWindow || !win.scope)return;
	if(this.selectedWindow && this.selectedWindow.ondeselect)
		this.selectedWindow.ondeselect();
		
	if(!win.alwaysOnTop){
		for(var a=0; a< this.windows.length; a++){
			if(this.windows[a] == win){
				var tmp=this.windows.splice(a,1);
				for(var b=this.windows.length-1; b>=0; b--)
					if(!this.windows[b].alwaysOnTop)break;			
				this.windows.splice(b+1,0,tmp[0]);
				break;
			}
		}
	}
	
	for(var a=0; a< this.windows.length; a++){ // no need to restack all windows...
		this.windows[a].win.style.zIndex=(this.opts.baseZIndex + a);
		this.windows[a].win.className=this.opts.classWindow;
		if(this.windows[a].taskbarIcon)
			this.windows[a].taskbarIcon.className=this.opts.classIcon;
	}
	win.win.style.display = '';
	win.win.style.visibility = 'visible';
	if(!this.opts.alwaysShowIcons && win.taskbarIcon != null){
		win._removeTaskbarIcon();
	}
	win.win.className=this.opts.classActiveWindow;
	if(win.taskbarIcon)
		win.taskbarIcon.className=this.opts.classActiveIcon;
	this.selectedWindow=win;
	if(win.state=='icon' || win.state=='hidden'){
		win.state=win.prvState;
		win.prvState=null;
	}
	if(win.onselect)win.onselect();
};


jwim.Manager.prototype._destroyWindow = function(w) {
	for(var a=0; a< this.windows.length; a++){
		if(this.windows[a] == w){	
			if(!this.windows[a]._unload(false)) {
			    return false;
			}
			
			//this.opts.container.removeChild(this.windows[a].win);
			this.windows[a].getContainer().removeChild(this.windows[a].win);
			if(this.windows[a].taskbarIcon != null){				
				this.windows[a]._removeTaskbarIcon();
			}
			// save a reference to removed win to handle onclose() event
			var closed = this.windows.splice(a,1)[0];
			for(var b=0; b< this.windows.length; b++){
				this.windows[b].win.style.zIndex = (this.opts.baseZIndex + b);
			}
			if(typeof closed.onclose === 'function') {
			    closed.onclose();
			    closed.onclose = null;
			}
			
			closed.scope = null;
			closed = null;	
			
			var fw = this._getFirstVisibleWindow();
			if(fw) {
			    fw.select();
			}
			
			return;
		}
	}
	
	return null;
};


jwim.Manager.prototype._getFirstVisibleWindow=function(){
	for(var a = (this.windows.length-1); a>=0 ; a--){
		if(this.windows[a].win.style.visibility != 'hidden')
			return this.windows[a];
	}
	
	return null;
};


jwim.Manager.prototype._resizeIcons=function(){

	function gs(e,p){
		var n = parseInt(jwim.Utils.getStyle(e,p));
		return ( isNaN(n) ? 0 : n );
	}
	
	var a;
	var icns=[];
	//save icons attached to default icons container
	for(a=0; a<this.windows.length;a++){
		if(this.windows[a].taskbarIcon && this.windows[a].taskbarIcon.parentNode == this.opts.taskbar)
			icns.push(this.windows[a].taskbarIcon);
	}
	
	if(icns.length < 1)return;
	
	var tbw = this.opts.taskbar.clientWidth - gs(this.opts.taskbar,'padding-left') - gs(this.opts.taskbar,'padding-right') - 1;
	var iw = parseInt(tbw/icns.length);
	
	for(a=0; a<icns.length;a++){		
		var Dw = ( icns[a].offsetWidth + gs(icns[a],'margin-left') + gs(icns[a],'margin-right') ) - gs(icns[a],'width');		
		if( (this.opts.iconWidth + Dw) > iw){
			icns[a].style.width=(iw-Dw-1)+'px';		
		} else {
			icns[a].style.width = this.opts.iconWidth + 'px';
		}
	}
}	



/* - - WINDOW CLASS - - */
// constructor
jwim.Window = function(opts, manager){
	this.wm = manager;
	this.manager = manager;
	this.id = opts.id || manager._getNewId();	
	this.w = (typeof opts.width == 'number' ?  opts.width : manager.opts.defaultWidth);
	this.h = (typeof opts.height == 'number' ?  opts.height : manager.opts.defaultHeight);
	this.x = (typeof opts.x == 'number' ?  opts.x : manager.opts.defaultX);
	this.y = (typeof opts.y == 'number' ?  opts.y : manager.opts.defaultY);
	if (opts.centered) {
	    this.x = (manager.getContainerWidth() - this.w)/2;
	    this.y = (manager.getContainerHeight() - this.h)/2;
	    if (this.x < 0) {
	        this.x = 0;
	    }
	    if (this.y < 0) {
	        this.y = 0;
	    }
	}
	
	this.userW = this.w;
	this.userH = this.h;
	this.userX = null; //this.x; - init by createWindow
	this.userY = null; //this.y;
	this.movable = (typeof opts.movable == 'undefined' ? manager.opts.movable : opts.movable);
	this.alwaysOnTop = opts.alwaysOnTop || false;
	this.titleText = opts.title || '';
	this.title = null;
	this.titleSpan = null;
	this.iconImageURL = opts.iconImageURL || '';
	this.state = 'window';
	this.prvState = null;
	this.win = null;
	this.content = null;
	this.taskbarIcon = null;
	this.taskbarIconSpan = null;
	this.taskbarIconImage = null;
	this.currentUrl = null;
	this.afterLoad = opts.afterLoad || manager.opts.afterLoad ;
	
	//initizlized via in-win scripts		
	this.onunload = null;
	this.onselect = null;
	this.onresize = null;
	this.onmove = null;
	this.oniconize = null;
	this.ondeselect = null;
	this.onclose = null;
	this.onhttperror = null;

	this.scope = new jwim.Scope(this);
	
	this.components = {
		titlebar:null,
		window:null,
		content:null,
		maximizer:null,
		iconizer:null,
		close:null,
		icon:null,
		loading:null,
		iconImage: null
	};
	
	// dragging
	this.resizing = false;
	this.moving = false;
	this.closeConfirm = '';
};


jwim.Window.prototype.attachEvents = function() {
    if (this.components.iconImage) {
        jwim.Utils.addEvent(this.components.iconImage, 'mousedown',  jwim.Utils.bind(this.onIconMouseDown, this));
        jwim.Utils.addEvent(this.components.iconImage, 'touchstart', jwim.Utils.bind(this.onIconMouseDown, this));
        jwim.Utils.addEvent(this.components.iconImage, 'mousemove', jwim.Utils.bind(this.onIconMouseMove, this));
        jwim.Utils.addEvent(this.components.iconImage, 'touchmove', jwim.Utils.bind(this.onIconMouseMove, this));
        jwim.Utils.addEvent(this.components.iconImage, 'mouseup',  jwim.Utils.bind(this.onIconMouseUp, this));
        jwim.Utils.addEvent(this.components.iconImage, 'mouseout', jwim.Utils.bind(this.onIconMouseUp, this));
        jwim.Utils.addEvent(this.components.iconImage, 'touchend', jwim.Utils.bind(this.onIconMouseUp, this));
    }
    
    if (this.titleSpan) {
        jwim.Utils.addEvent(this.titleSpan, 'mousedown',  jwim.Utils.bind(this.onTitleMouseDown, this));
        jwim.Utils.addEvent(this.titleSpan, 'touchstart', jwim.Utils.bind(this.onTitleMouseDown, this));
        jwim.Utils.addEvent(this.titleSpan, 'mousemove', jwim.Utils.bind(this.onTitleMouseMove, this));
        jwim.Utils.addEvent(this.titleSpan, 'touchmove', jwim.Utils.bind(this.onTitleMouseMove, this));
        jwim.Utils.addEvent(this.titleSpan, 'mouseup',  jwim.Utils.bind(this.onTitleMouseUp, this));
        jwim.Utils.addEvent(this.titleSpan, 'mouseout', jwim.Utils.bind(this.onTitleMouseUp, this));
        jwim.Utils.addEvent(this.titleSpan, 'touchend', jwim.Utils.bind(this.onTitleMouseUp, this));
    }
    
    if (this.components.close) {
        jwim.Utils.addEvent(this.components.close, 'click', jwim.Utils.bind(this.onCloseClick, this));
    }
    
    if (this.components.maximizer) {
        jwim.Utils.addEvent(this.components.maximizer, 'click', jwim.Utils.bind(this.onMaxClick, this));
    }
    
    if (this.components.iconizer) {
        jwim.Utils.addEvent(this.components.iconizer, 'click', jwim.Utils.bind(this.onMinClick, this));
    }
};

jwim.Window.prototype.detachEvents = function() {
    if (this.components.iconImage) {
        jwim.Utils.removeEvent(this.components.iconImage, 'mousedown',  jwim.Utils.bind(this.onIconMouseDown, this));
        jwim.Utils.removeEvent(this.components.iconImage, 'touchstart', jwim.Utils.bind(this.onIconMouseDown, this));
        jwim.Utils.removeEvent(this.components.iconImage, 'mousemove', jwim.Utils.bind(this.onIconMouseMove, this));
        jwim.Utils.removeEvent(this.components.iconImage, 'touchmove', jwim.Utils.bind(this.onIconMouseMove, this));
        jwim.Utils.removeEvent(this.components.iconImage, 'mouseup',  jwim.Utils.bind(this.onIconMouseUp, this));
        jwim.Utils.removeEvent(this.components.iconImage, 'mouseout', jwim.Utils.bind(this.onIconMouseUp, this));
        jwim.Utils.removeEvent(this.components.iconImage, 'touchend', jwim.Utils.bind(this.onIconMouseUp, this));
    }
    
    if (this.titleSpan) {
        jwim.Utils.removeEvent(this.titleSpan, 'mousedown',  jwim.Utils.bind(this.onTitleMouseDown, this));
        jwim.Utils.removeEvent(this.titleSpan, 'touchstart', jwim.Utils.bind(this.onTitleMouseDown, this));
        jwim.Utils.removeEvent(this.titleSpan, 'mousemove', jwim.Utils.bind(this.onTitleMouseMove, this));
        jwim.Utils.removeEvent(this.titleSpan, 'touchmove', jwim.Utils.bind(this.onTitleMouseMove, this));
        jwim.Utils.removeEvent(this.titleSpan, 'mouseup',  jwim.Utils.bind(this.onTitleMouseUp, this));
        jwim.Utils.removeEvent(this.titleSpan, 'mouseout', jwim.Utils.bind(this.onTitleMouseUp, this));
        jwim.Utils.removeEvent(this.titleSpan, 'touchend', jwim.Utils.bind(this.onTitleMouseUp, this));
    }
    
    if (this.components.close) {
        jwim.Utils.removeEvent(this.components.close, 'click', jwim.Utils.bind(this.onCloseClick, this));
    }
    
    if (this.components.maximizer) {
        jwim.Utils.removeEvent(this.components.maximizer, 'click', jwim.Utils.bind(this.onMaxClick, this));
    }
    
    if (this.components.iconizer) {
        jwim.Utils.removeEvent(this.components.iconizer, 'click', jwim.Utils.bind(this.onMinClick, this));
    }
};

// window event handlers
jwim.Window.prototype.onTitleMouseDown = function(e) {
    this.select();
    jwim.Utils.stopEvent(e);
    
	if (!this.movable) {
	    return;
	}
	
    this.moving = true;
    
	if (!e) {
	    e = window.event;	
	}
    var xy = jwim.Utils.getEventXY(e, this.titleSpan);
	this.wm.mouse.click.x = xy.x - this.x;
	this.wm.mouse.click.y = xy.y - this.y;
};

jwim.Window.prototype.onTitleMouseMove = function(e) {
    jwim.Utils.stopEvent(e);
    
    if (!this.moving) { 
        return;
    }
    
    // move window
	if(!e) {
	    e = window.event;
	}
	this.state = 'window';
	
	var xy = jwim.Utils.getEventXY(e, this.titleSpan);
	
	this.wm.mouse.cur.x = xy.x;
	this.wm.mouse.cur.y = xy.y;
	
	var y = (this.wm.mouse.cur.y - this.wm.mouse.click.y);
	var x = (this.wm.mouse.cur.x - this.wm.mouse.click.x);
	
	if(this.wm.opts.containerBoundaries > 0) {
		// these vals may be cached while moving..
		var minx = -1*(this.getWidth() - this.wm.opts.containerBoundaries);
		var maxx = this.getContainerWidth() - this.wm.opts.containerBoundaries;
		var maxy = this.getContainerHeight() - this.wm.opts.containerBoundaries;
		
		if(x < minx) x = minx;
		if(x > maxx) x = maxx;		
		if(y > maxy) y = maxy;
	}
	
	if(this.wm.opts.containerBoundaries > -1) {		
		if(y < 0) y = 0;
	}
	
	this.win.style.left = x + 'px';
	this.win.style.top  = y + 'px';

	if(typeof this.onmove === 'function') {
	    this.onmove(x,y);
    }
};

jwim.Window.prototype.onTitleMouseUp = function(e) {
    this.moving = false;
    jwim.Utils.stopEvent(e);
    
	if(this.state === 'window') { // if state=='window'  resize or move have been called
		this.w = parseInt(this.win.style.width, 10);
		this.h = parseInt(this.win.style.height, 10);
		this.x = parseInt(this.win.style.left, 10);
		this.y = parseInt(this.win.style.top, 10);
		this.userW = this.w;
		this.userH = this.h;
		this.userX = this.x
		this.userY = this.y
	}
};

jwim.Window.prototype.onIconMouseDown = function(e) {
    this.select();
    this.resizing = true;
    jwim.Utils.stopEvent(e);
    
	if (!e) {
	    e = window.event;	
	}
	
    var xy = jwim.Utils.getEventXY(e, this.components.iconImage);
    
	this.wm.mouse.click.rx = xy.x;
	this.wm.mouse.click.ry = xy.y;
	this.wm.mouse.click.x = xy.x - this.x;
    this.wm.mouse.click.y = xy.y - this.y;
};

jwim.Window.prototype.onIconMouseMove = function(e) {
    jwim.Utils.stopEvent(e);
    
    if (!this.resizing) {
        return;
    }
	
	this.state = 'window';
	if(!e) {
	    e = window.event;
	}
	
	var xy = jwim.Utils.getEventXY(e, this.components.iconImage);
	
	this.wm.mouse.cur.x = xy.x;
	this.wm.mouse.cur.y = xy.y;
	
	// move 
    y = (this.wm.mouse.cur.y - this.wm.mouse.click.y);
	x = (this.wm.mouse.cur.x - this.wm.mouse.click.x);
	if(this.wm.opts.containerBoundaries > 0) {
		// these vals may be cached while moving..
		var minx = -1*(this.getWidth() - this.wm.opts.containerBoundaries);
		var maxx = this.getContainerWidth() - this.wm.opts.containerBoundaries;
		var maxy = this.getContainerHeight() - this.wm.opts.containerBoundaries;
		
		if(x < minx) x = minx;
		if(x > maxx) x = maxx;		
		if(y > maxy) y = maxy;
	}
	if(this.wm.opts.containerBoundaries > -1) {		
		if(y < 0) y = 0;
	}
	
	this.win.style.top  = y + 'px';
	this.win.style.left = x + 'px';	
	
	// resize
	var h = (this.h + (this.wm.mouse.click.ry - this.wm.mouse.cur.y));		
	var w = (this.w + (this.wm.mouse.click.rx - this.wm.mouse.cur.x));
	
	if(w < 90) w = 90;
	if(h < 50) h = 50;
	
	this._setSize(w,h,true,'resize');
};

jwim.Window.prototype.onIconMouseUp = function(e) {
    this.resizing = false;
    jwim.Utils.stopEvent(e);
    
	if(this.state === 'window') { // if state=='window'  resize or move have been called
		this.w = parseInt(this.win.style.width, 10);
		this.h = parseInt(this.win.style.height, 10);
		this.x = parseInt(this.win.style.left, 10);
		this.y = parseInt(this.win.style.top, 10);
		this.userW = this.w;
		this.userH = this.h;
		this.userX = this.x
		this.userY = this.y
	}
};

jwim.Window.prototype.onCloseClick = function(e) {
    this.select();
    jwim.Utils.stopEvent(e);
    
    if (this.closeConfirm) {
        if (window.confirm(this.closeConfirm)) {
            this.close();
        } else {
            this._iconify();
        }
    } else {
        this.close();
    }
};
jwim.Window.prototype.onMaxClick = function(e) {
    this.select();
    this._maximize();
    jwim.Utils.stopEvent(e);
};
jwim.Window.prototype.onMinClick = function(e) {
    this.select();
    this._iconify();
    jwim.Utils.stopEvent(e);
};

jwim.Window.prototype.getElement=function(eid,o){
	if(!o) var o = this.content;			
	for(var a=0; a<o.childNodes.length; a++){
		if(o.childNodes[a].getAttribute && o.childNodes[a].getAttribute("data-wid") == eid ){ 
			return o.childNodes[a];
		} 
		var t=this.getElement(eid,o.childNodes[a]);
		if(t)return t;
	}
	return null;
};


jwim.Window.prototype.setState=function(state){
	switch(state){
		case 'maximized':
			if(this.state=='maximized') return;
			this._maximize();
			return;
		case 'window':
			if(this.state=='maximized'){
				this._maximize();
				return;
			}
			this.state='window';
			this.select();
			return;
		case 'icon':
			this._iconify();
			return;
		case 'hidden':
			this.hide();
			return;
	}
}


jwim.Window.prototype.setSize=function(w,h){
	this.state='window';
	this._setSize(w,h,false,'resize');
	this.userW=w;
	this.userH=h;
};


jwim.Window.prototype.setPosition=function(x,y){
	this._setPosition(x,y);
	if(this.onmove) 
		this.onmove(x,y);

};


jwim.Window.prototype._setPosition=function(x,y){ 
	this.state='window';
	this.win.style.left=x+'px';
	this.win.style.top=y+'px'
	this.x = this.userX = x;
	this.y = this.userY = y ;
};

jwim.Window.prototype.moveToCenter=function(){
    var x,y;
    x = (this.getContainerWidth()-this.w)/2;
    y = (this.getContainerHeight()-this.h)/2;
    if (y<0) y=0;
    this.setPosition(x,y);
};

jwim.Window.prototype.close=function(){
	this.manager._destroyWindow(this);
};

jwim.Window.prototype.select=function(){
	this.manager._selectWindow(this);
};


jwim.Window.prototype.setContent=function(html,element){
	//var js, re = new RegExp('<script\b[\s\S]*?>([\s\S]*?)<\/script','gi');
	// testre doesnt need the g modifier...
	var js, testre = /<script\b[\s\S]*?>([\s\S]*?)<\/script/i;
	var afterLoad=null;
	
	if(!element){
		if( !this._unload(true) ) return false; 		
		element=this.content;
		afterLoad=this.afterLoad;
	}
	
	element.innerHTML=html.replace(/<script.*?>[\s\S]*?<\/.*?script>/gi,"");			
	this.convertElementsAttributes(element);
	
	// testre is a dirty hack to work around a FF bug
	// it seems that FF doesnt allow nested setContent calls (i mean calling setContent from a 
	// content loaded with setContent).. Infact the second (innermost) call will always get
	// the re.exec of the prv call even if html doesnt contain scripts . . mha.. 
	// The nature of this bug is not exactly clear to me.. but this works
	if(testre.test(html)){
		var re = /<script\b[\s\S]*?>([\s\S]*?)<\/script/gi;
		while (js = re.exec(html)) {
			this.scope._eval(js[1]);
		}
	}
	
	if(afterLoad)
		afterLoad(this);
	
};


jwim.Window.prototype.convertElementsAttributes=function(o){
	var evnames=['onchange','onsubmit','onreset','onselect','onblur','onfocus','onkeydown','onkeypress','onkeyup','onclick','ondblclick','onmousedown','onmousemove','onmouseout','onmouseover','onmouseup'];
	var code;
	function attachEventCode(code,thisw){
		//for IE <=7.. it may (MAY) cause conflicts if convertElementsAttributes
		// is called against a three containing objects with events attached
		if(typeof code != 'string'){
			code = code.toString();
			code=code.substr(code.indexOf('{')+1);
			code=code.substr(0,code.lastIndexOf('}'));
		}
		return function(event){
			if(!event) var event=window.event; 
			//take care of: this, event, thisw and return value..
			eval("var event_attribute=function(event,thisw){"+code+"}");
			return event_attribute.apply(this,[event,thisw]);
		}
	};	

	var elements=o.getElementsByTagName("*");
	for(var a=0; a<elements.length; a++){
		var c=elements[a];

		for(var b=0; b<evnames.length;b++){
			if(c.getAttribute && (code = c.getAttribute(evnames[b]))){					
				c[evnames[b]]=attachEventCode(code,this);
			}
		}
		
		if(c.tagName=='A' && c.target=="" &&  (code = c.getAttribute("href"))) {
			if(code.toLowerCase() != 'javascript:void(0)' && code != '#'){
				c.onclick=(function(w,c){return function(){ // since code will change we also make a copy of code 
					w.loadUrl(c);
					return false;
				}})(this,code);
			}
		}
	}

};



jwim.Window.prototype.loadUrl=function(url,onload,onerror){
	var req = false;

	this.showLoading();
	// branch for native XMLHttpRequest object
	if(window.XMLHttpRequest  && !(window.ActiveXObject)) {
		try {
			req = new XMLHttpRequest();
		} catch(e) {
			req = false;
		}
	// branch for IE/Windows ActiveX version
	} else if(window.ActiveXObject) {
		try {
			req = new ActiveXObject("Msxml2.XMLHTTP");
		} catch(e) {
			try {
				req = new ActiveXObject("Microsoft.XMLHTTP");
			} catch(e) {
				req = false;
			}
		}
	}
	if(!req) {
		alert("AJAX not supported by this browser");
		return false;
	}
	req.onreadystatechange = (function(w) {return function(){
		if (req.readyState == 4) {
			w.showLoading(false);
			switch (req.status) {
				case 200: // OK
					w.currentUrl=url;
					w.setContent(req.responseText);	 	
					if(onload)
						onload(w);
						
					break;
				default:
				    if(onerror) {
				        onerror(w);
				    }
					if(w.onhttperror){
						w.onhttperror(req,url);
						return;
					}
					
					if(w.manager.opts.httpErrorHandler){
						w.manager.opts.httpErrorHandler(req,url,w);
						return;
					}
					
					alert("HTTP Error: " +req.status+"\n"+url);
			}
		}
	}})(this);
	
	// cache prevention code ripped from jquery 
	if(!this.manager.opts.cacheXHR){
		var ts = (new Date).getTime();	
		// try replacing _= if it is there
		var ret = url.replace(/(\?|&)_=.*?(&|$)/, "$1_=" + ts + "$2");
		// if nothing was replaced, add timestamp to the end
		url = ret + ((ret === url) ? ( (/\?/).test(url) ? "&" : "?") + "_=" + ts : "");
	}	
	req.open("GET", url, true);
	req.send("");
	
};

jwim.Window.prototype.loadUrlX=function(url,onload){
	var req = false;

	this.content.innerHTML = '';
	this.showLoading();
	
	// add an iframe tag into content div
	var frame = document.createElement('iframe');
	frame.className = this.manager.opts.classFrame;
	frame.setAttribute('data-wid', 'theFrame');
	
	// cache prevention code ripped from jquery 
	if(!this.manager.opts.cacheXHR){
		var ts = (new Date).getTime();	
		// try replacing _= if it is there
		var ret = url.replace(/(\?|&)_=.*?(&|$)/, "$1_=" + ts + "$2");
		// if nothing was replaced, add timestamp to the end
		url = ret + ((ret === url) ? ( (/\?/).test(url) ? "&" : "?") + "_=" + ts : "");
	}
	frame.src = url;

    jwim.Utils.addEvent(frame, 'load', (function(w) { return function() {
	    w.currentUrl = url;
	    w.showLoading(false);
	    // call the outside handler
	    if(onload) {
            onload(w);
	    }
	}})(this));
	
	// add this iframe to content
	this.content.appendChild(frame);
};

jwim.Window.prototype.showLoading = function(show){
    if (typeof show == 'undefined' || show ) {
        this.loading.style.display = '';
        this.loading.style.visibility = 'visible';
    } else {
        this.loading.style.visibility = 'hidden';
        this.loading.style.display = 'none';
    }
};


jwim.Window.prototype.setTitle=function(title){
	if(title && this.title){
		this.titleSpan.innerHTML=title;
		this.titleText=title;
	}
	if(title && this.taskbarIcon){
		this.taskbarIconSpan.innerHTML=title;
		this.taskbarIcon.setAttribute('title',title);
	}
};

jwim.Window.prototype.setIconImage = function(iconUrl) {
    if (iconUrl && iconUrl !== this.iconImageURL) {
        this.iconImageURL = iconUrl;
    } else {
        return;
    }
    
    if (this.components.iconImage) {
        this.components.iconImage.src = iconUrl;
    }
    if (this.taskbarIconImage) {
        this.taskbarIconImage.src = iconUrl;
    }
};

jwim.Window.prototype.setMovable=function(v){ 
	this.movable=v;
};


jwim.Window.prototype.setAlwaysOnTop=function(v){
	if(v)this.select();
	this.alwaysOnTop=v;
};


jwim.Window.prototype.getComponent=function(elem){
	return this.components[elem];
};


jwim.Window.prototype.isMovable=function(){ 
	return this.movable;
};


jwim.Window.prototype.isAlwaysOnTop=function(){ 
	return this.alwaysOnTop;
};

jwim.Window.prototype.isSelected=function() {
    return (this === this.getManager().getSelectedWindow()); 
};

jwim.Window.prototype.getWidth=function(){ 
	return this.w;
};


jwim.Window.prototype.getHeight=function(){
	return this.h;
};


jwim.Window.prototype.getX=function(){ 
	return this.x;
};


jwim.Window.prototype.getY=function(){ 
	return this.y;
};


jwim.Window.prototype.getId=function(){ 
	return this.id;
};


jwim.Window.prototype.getTitle=function(){
	return this.titleText;
};


jwim.Window.prototype.getCurrentUrl=function(full){ 
	// if not full remove anti-caching url variable
	return (this.manager.opts.cacheXHR || full ? this.currentUrl : this.currentUrl.replace(/(\?|&)_=.*/,'') );
};


jwim.Window.prototype.getState=function(){ 
	return this.state;
};


jwim.Window.prototype.getManager=function(){
	return this.manager;
};

jwim.Window.prototype.getContentWidth=function(){ 
	return parseInt(this.content.style.width);
};


jwim.Window.prototype.getContentHeight=function(){ 
	return parseInt(this.content.style.height);
};


jwim.Window.prototype.getContainer=function(){ 
	return this.win.parentNode;
};


jwim.Window.prototype.getContainerWidth=function(){ 
	var c =this.getContainer();
	if( c == document.body)
		return jwim.Utils.getBodySize().width;
		
	return c.clientWidth;
};


jwim.Window.prototype.getContainerHeight=function(){ 
	var c =this.getContainer();
	if( c == document.body)
		return jwim.Utils.getBodySize().height;
		
	return c.clientHeight;
};


jwim.Window.prototype.attachTo=function(el){
	el = el || this.manager.opts.container;
	el.appendChild(this.win);
};



jwim.Window.prototype._maximize=function(){
	
	if(this.state != 'maximized'){
		var w,h;
		var Dw= this.win.offsetWidth - parseInt(this.win.style.width);
		var Dh= this.win.offsetHeight - parseInt(this.win.style.height);

		
		this.win.style.top=0+'px';
		this.win.style.left=0+'px';
		this.x = this.y = 1;
		this.state='maximized'; 
		w=this.getContainerWidth()  - Dw;
		h=this.getContainerHeight() - Dh;
		this._setSize(w,h,false,'maximize');

	} else {
		this.state='window';
		//alert(this.userW);
		this._setSize(this.userW, this.userH,false,'restore');
		this._setPosition(this.userX,this.userY);
	}

};


// action is used to tell enevn handler what fired the event.. if action=='' event is NOT fired
jwim.Window.prototype._setSize=function(w,h,isResize,action){
	var off=0;
	this.win.style.height = h +'px';
	this.win.style.width = w +'px';


	var contw = w - (this.content.offsetWidth - parseInt(this.content.style.width));
	var conth = h - (this.content.offsetHeight-parseInt(this.content.style.height)) - this.content.offsetTop;
	
	this.content.style.height = conth +'px';
	this.content.style.width = contw + 'px';
	if(!isResize){
		this.w=w;
		this.h=h;
	}
	
	if(action && this.onresize) 
		this.onresize(w,h,action);

}


jwim.Window.prototype.autoSize=function(){ // maybe in the future...
	this.win.style.height= 0 +'px';
	this.win.style.width=  0 +'px';
	this.content.style.height=0 +'px';
	this.content.style.width=0 + 'px';
	var w =this.content.scrollWidth+30,
		h=this.content.scrollHeight+70;
	this.setSize(w,h);
	this.state='window';

}



jwim.Window.prototype.hide = function(){ 
	this.prvState = this.state;
	this.state = 'hidden';
	this.win.style.visibility = 'hidden';
	this.win.style.display = 'none';
};


jwim.Window.prototype._iconify = function() {
	if(!this.manager.opts.taskbar || this.state == 'icon') {
	    return;
	}
	
	if(!this.manager.opts.alwaysShowIcons){
		this._createTaskbarIcon();	
	}
	
	this.taskbarIcon.className = this.manager.opts.classIcon;
	if(this.manager.selectedWindow == this) {
	    this.manager.selectedWindow = null;
	}
	
	this.hide();
	this.state = 'icon';
	
	var fw = this.manager._getFirstVisibleWindow();
	if (fw) {
	    fw.select();
	}

	if(this.oniconize) {
	    this.oniconize();
	}
};


jwim.Window.prototype._createTaskbarIcon=function(){
	if(!this.manager.opts.taskbar)return;
	//var width=this.manager.opts.iconWidth;
	this.taskbarIcon=document.createElement('div');
	if (this.manager.opts.showIconImage) {
		this.taskbarIconImage = document.createElement('img');
		this.taskbarIconImage.src = this.iconImageURL;
		this.taskbarIconImage.setAttribute('title', this.titleText);
		this.taskbarIcon.appendChild(this.taskbarIconImage);
    }
	this.taskbarIconSpan=document.createElement('span');
	this.taskbarIcon.className=this.manager.opts.classIcon;
	this.taskbarIconSpan.innerHTML=this.titleText;
	this.taskbarIcon.setAttribute('title',this.titleText);
	this.taskbarIcon.style.width=this.manager.opts.iconWidth + 'px';
	
	jwim.Utils.addEvent(this.taskbarIcon, 'click', jwim.Utils.bind(this.onTaskbarIconClick, this));
	jwim.Utils.addEvent(this.taskbarIcon, 'dblclick', jwim.Utils.bind(this.onTaskbarIconDoubleClick, this));
	
	this.taskbarIcon.appendChild(this.taskbarIconSpan);
	this.manager.opts.taskbar.appendChild(this.taskbarIcon);
	this.components.icon=this.taskbarIcon;
	if(this.manager.opts.resizeIcons) {
		this.manager._resizeIcons();
    }
};


jwim.Window.prototype._removeTaskbarIcon=function(){
    jwim.Utils.removeEvent(this.taskbarIcon, 'click', jwim.Utils.bind(this.onTaskbarIconClick, this));
	jwim.Utils.removeEvent(this.taskbarIcon, 'dblclick', jwim.Utils.bind(this.onTaskbarIconDoubleClick, this));
	// note that taskbaricon may be attached somewhere else at runtime
	this.taskbarIcon.parentNode.removeChild(this.taskbarIcon);
	this.taskbarIcon=null;
	if(this.manager.opts.resizeIcons) this.manager._resizeIcons();
};

jwim.Window.prototype.onTaskbarIconClick = function(e) {
    if (this.isSelected()) {
	    this._iconify();
	} else {
	    this.select();
	} 
};
jwim.Window.prototype.onTaskbarIconDoubleClick = function(e) {
    this.moveToCenter();
};


//fires onunload event and clear window events
jwim.Window.prototype._unload = function(clearAll){
	if(typeof this.onunload === 'function') {
	    if (!this.onunload()) {
	        return false;
	    }
	}
	// clear all event listeners
	this.detachEvents();
	
	this.onunload = null;
	this.onselect = null;
	this.onresize = null;
	this.onmove = null;
	this.oniconize = null;
	this.ondeselect = null;
	this.onhttperror = null;
	
	if(clearAll){
		this.scope = new jwim.Scope(this);
	}
	
	return true;
};


/* - - UTILS - - */

jwim.Utils.BROWSER = (function() {
    var name = "";
    var ua = navigator.userAgent.toLowerCase();
    if (ua.indexOf("opera") != -1) {
        name = "opera";
    } else if (ua.indexOf("msie") != -1) {
        name = "msie";
    } else if (ua.indexOf("safari") != -1) {
        name = "safari";
    } else if (ua.indexOf("mozilla") != -1) {
        if (ua.indexOf("firefox") != -1) {
            name = "firefox";
        } else {
            name = "mozilla";
        }
    }
    return name;
})();

jwim.Utils.ISGECKO = (function() {
    var ua = navigator.userAgent.toLowerCase();
    return ua.indexOf("webkit") == -1 && ua.indexOf("gecko") != -1;
})();

jwim.Utils.getViewportElement = function() {
    var viewportElement = arguments.callee.viewportElement;
    if (viewportElement == undefined) {
        viewportElement = (jwim.Utils.BROWSER == "msie" &&
            document.compatMode != 'CSS1Compat') ? document.body :
            document.documentElement;
        arguments.callee.viewportElement = viewportElement;
    }
    return viewportElement;
};

jwim.Utils.pagePosition =  function(forElement) {
    // NOTE: If element is hidden (display none or disconnected or any the
    // ancestors are hidden) we get (0,0) by default but we still do the
    // accumulation of scroll position.

    var pos = [0, 0];
    var viewportElement = jwim.Utils.getViewportElement();
    if (!forElement || forElement == window || forElement == viewportElement) {
        // viewport is always at 0,0 as that defined the coordinate system for
        // this function - this avoids special case checks in the code below
        return pos;
    }

    // Gecko browsers normally use getBoxObjectFor to calculate the position.
    // When invoked for an element with an implicit absolute position though it
    // can be off by one. Therefore the recursive implementation is used in
    // those (relatively rare) cases.
    var BUGGY_GECKO_BOX_OBJECT =
        jwim.Utils.ISGECKO && document.getBoxObjectFor &&
        jwim.Utils.getStyle(forElement, 'position') == 'absolute' &&
        (forElement.style.top == '' || forElement.style.left == '');

    var parent = null;
    var box;

    if (forElement.getBoundingClientRect) { // IE
        box = forElement.getBoundingClientRect();
        var scrollTop = viewportElement.scrollTop;
        var scrollLeft = viewportElement.scrollLeft;

        pos[0] = box.left + scrollLeft;
        pos[1] = box.top + scrollTop;

    } else if (document.getBoxObjectFor && !BUGGY_GECKO_BOX_OBJECT) { // gecko
        // Gecko ignores the scroll values for ancestors, up to 1.9.  See:
        // https://bugzilla.mozilla.org/show_bug.cgi?id=328881 and
        // https://bugzilla.mozilla.org/show_bug.cgi?id=330619

        box = document.getBoxObjectFor(forElement);
        var vpBox = document.getBoxObjectFor(viewportElement);
        pos[0] = box.screenX - vpBox.screenX;
        pos[1] = box.screenY - vpBox.screenY;

    } else { // safari/opera
        pos[0] = forElement.offsetLeft;
        pos[1] = forElement.offsetTop;
        parent = forElement.offsetParent;
        if (parent != forElement) {
            while (parent) {
                pos[0] += parent.offsetLeft;
                pos[1] += parent.offsetTop;
                parent = parent.offsetParent;
            }
        }

        var browser = jwim.Utils.BROWSER;

        // opera & (safari absolute) incorrectly account for body offsetTop
        if (browser == "opera" || (browser == "safari" &&
              jwim.Utils.getStyle(forElement, 'position') == 'absolute')) {
            pos[1] -= document.body.offsetTop;
        }

        // accumulate the scroll positions for everything but the body element
        parent = forElement.offsetParent;
        while (parent && parent != document.body) {
            pos[0] -= parent.scrollLeft;
            // see https://bugs.opera.com/show_bug.cgi?id=249965
            if (browser != "opera" || parent.tagName != 'TR') {
                pos[1] -= parent.scrollTop;
            }
            parent = parent.offsetParent;
        }
    }
    
    return pos;
};

jwim.Utils.getEventXY = function(evt, element) {
        evt = jwim.Utils.handleBrowserEvent(evt);
        
        if (!element.scrolls) {
            var viewportElement = jwim.Utils.getViewportElement();
            element.scrolls = [
                viewportElement.scrollLeft,
                viewportElement.scrollTop
            ];
        }

        if (!element.lefttop) {
            element.lefttop = [
                (document.documentElement.clientLeft || 0),
                (document.documentElement.clientTop  || 0)
            ];
        }
        
        if (!element.offsets) {
            element.offsets = jwim.Utils.pagePosition(element);
        }

        var xy = {
            x: (evt.clientX + element.scrolls[0]) - element.offsets[0] - element.lefttop[0], 
            y: (evt.clientY + element.scrolls[1]) - element.offsets[1] - element.lefttop[1]
        };
        
    return xy;    
};

/**
     * APIFunction: bind
     * Bind a function to an object. Method to easily create closures with 'this' altered.
     * 
     * Parameters:
     * func - {Function} Input function.
     * object - {Object} The object to bind to the input function (as this).
     * 
     * Returns:
     * {Function} A closure with 'this' set to the passed in object.
     */
jwim.Utils.bind = function(func, object) {
        // create a reference to all arguments past the second one
        var args = Array.prototype.slice.apply(arguments, [2]);
        return function() {
            // Push on any additional arguments from the actual function call.
            // These will come after those sent to the bind call.
            var newArgs = args.concat(
                Array.prototype.slice.apply(arguments, [0])
            );
            return func.apply(object, newArgs);
        };
};


jwim.Utils.addEvent = function(obj, name, callback) {
	if (obj.addEventListener) {
	    obj.addEventListener(name, callback, false);
	} else if (obj.attachEvent) {
        obj.attachEvent('on' + name, callback); 
	} else {
	    obj['on'+name] = callback;
	}
};


jwim.Utils.removeEvent = function(obj, name, callback){
	if (obj.removeEventListener) {
        obj.removeEventListener(name, callback, false);
	} else if (obj && obj.detachEvent) {
        obj.detachEvent('on' + name, callback);
	} else {
	    obj['on'+name] = null;
	}
};

jwim.Utils.stopEvent = function(event) {
    if (event.preventDefault) {
            event.preventDefault();
    } else {
            event.returnValue = false;
    }
    
    if (event.stopPropagation) {
            event.stopPropagation();
    } else {
        event.cancelBubble = true;
    }
};

jwim.Utils.handleBrowserEvent = function(evt) {
        // add clientX & clientY to all events - corresponds to average x, y
        var touches = evt.touches;
        if (touches && touches[0]) {
            var x = 0;
            var y = 0;
            var num = touches.length;
            var touch;
            for (var i=0; i<num; ++i) {
                touch = touches[i];
                x += touch.clientX;
                y += touch.clientY;
            }
            evt.clientX = x / num;
            evt.clientY = y / num;
        }
        
        return evt;
};

jwim.Utils.getBodySize = function() {
	var w = (window.innerWidth  || document.documentElement.clientWidth  || document.body.clientWidth);
	var h = (window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight);
	
	return {
	    width: w,
	    height: h
	};
};


jwim.Utils.camelize = function(str) {
        var oStringList = str.split('-');
        var camelizedString = oStringList[0];
        for (var i=1, len=oStringList.length; i<len; i++) {
            var s = oStringList[i];
            camelizedString += s.charAt(0).toUpperCase() + s.substring(1);
        }
        return camelizedString;
};


jwim.Utils.indexOf = function(array, obj) {
            // use the build-in function if available.
            if (typeof array.indexOf === "function") {
                return array.indexOf(obj);
            } else {
                for (var i = 0, len = array.length; i < len; i++) {
                    if (array[i] == obj) {
                        return i;
                    }
                }
                return -1;
            }
};


jwim.Utils.getStyle=function(element, style){
    var value = null;
    
    if (element && element.style) {
        value = element.style[jwim.Utils.camelize(style)];
        if (!value) {
                if (document.defaultView && 
                    document.defaultView.getComputedStyle) {
                    
                    var css = document.defaultView.getComputedStyle(element, null);
                    value = css ? css.getPropertyValue(style) : null;
                } else if (element.currentStyle) {
                    value = element.currentStyle[jwim.Utils.camelize(style)];
                }
        }
        
        var positions = ['left', 'top', 'right', 'bottom'];
        if (window.opera &&
            (jwim.Utils.indexOf(positions,style) != -1) &&
            (jwim.Utils.getStyle(element, 'position') == 'static')
        ) { 
                value = 'auto';
        }
    }
    
    return value == 'auto' ? null : value;
};

